package com.flutter.ble_demo;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.RelativeSizeSpan;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import com.borsam.ble.callback.BatteryCallback;
import com.borsam.ble.callback.BorsamBleGattCallback;
import com.borsam.ble.callback.SimpleBorsamBleDataCallback;
import com.borsam.blecore.exception.BleException;
import com.borsam.device.BorsamDevice;
import com.borsam.device.callback.DataPartTwoListener;
import com.borsam.device.callback.OnAddPointListener;
import com.borsam.jni.callback.HeatRateListener;
import com.borsam.widget.ECGView;
import com.flutter.ble_demo.utils.Base64;
import com.king.view.circleprogressview.CircleProgressView;

import java.util.Timer;
import java.util.TimerTask;

import io.flutter.embedding.android.FlutterActivity;


/**
 * @author Borsam Medical
 * @version 1.0
 **/
public class EcgViewActivity extends AppCompatActivity implements BorsamDevice.BorsamDeviceCodeCallback {
  private static final String TAG="EcgViewActivity";
  //We only receive 30s data
  private final float TOTAL_TIME = 30;
  private static final String BORSAM_DEVICE = "borsam_device";
  private BorsamDevice mBorsamDevice;
  private ECGView mECGView;
  private boolean mEnd;

  private boolean isStart;

  private Timer timer;
  public static   int countDown;

  private TaskHandler taskHandler;

  private CircleProgressView circleProgressView;

  private TextView ecgStatusText,batteryText,timeShowText,ecgValueText;
  private ImageView backImageView;
  //蓝牙状态监听
  private BluetoothStatusReceiver bluetoothStatusReceiver;

  public static void start(Context context, @NonNull BorsamDevice borsamDevice) {
    Intent starter = new Intent(context, com.flutter.ble_demo.EcgViewActivity.class);
    starter.putExtra(BORSAM_DEVICE, borsamDevice);
    context.startActivity(starter);
  }

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_ecgview);
    Toolbar toolbar = findViewById(R.id.toolbar);
    circleProgressView = findViewById(R.id.cpv);
    ecgStatusText = findViewById(R.id.tv_ecg_status);
    batteryText = findViewById(R.id.tv_battery);
    timeShowText = findViewById(R.id.tv_countdown);
    ecgValueText = findViewById(R.id.tv_ecg_value);
    backImageView = findViewById(R.id.iv_back);
    taskHandler = new TaskHandler();
    timer = new Timer();
    backImageView.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        finish();
      }
    });
    setSupportActionBar(toolbar);
    mBorsamDevice = getIntent().getParcelableExtra(BORSAM_DEVICE);
    mECGView = findViewById(R.id.ecgView);
    mECGView.setECGParams(mBorsamDevice);
    bluetoothStatusReceiver = new BluetoothStatusReceiver();
    IntentFilter intentFilter = new IntentFilter();
   // 监视蓝牙关闭和打开的状态
    intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);

   // 监视蓝牙设备与APP连接的状态
    intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
    registerReceiver(bluetoothStatusReceiver,intentFilter);
    //监听心率变化
    mBorsamDevice.setHeatRateListener(new HeatRateListener() {
      @Override
      public void onReceiver(int hrValue) {
        SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.valueOf(hrValue));
        SpannableString spannableString = new SpannableString("bpm");
        spannableString.setSpan(new RelativeSizeSpan(0.7f),0,spannableString.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE );
        stringBuilder.append(spannableString);
        ecgValueText.setText(stringBuilder);
      }
    });
    //IMPORTANT:set this listener to display data
    mBorsamDevice.setOnAddPointListener(new OnAddPointListener() {
      /**
       * Callback this method on add point
       * @param point ecg data
       * @param passageIndex passage number start with 1 not 0
       */
      @Override
      public void onAddPoint(int point, int passageIndex) {
        //IMPORTANT:Call this method ECG to display data
        mECGView.addPoint(point, passageIndex);
      }
    });
    connect();
  }

  public static class CountDownTask extends TimerTask{

    private TaskHandler taskHandler;

    public CountDownTask(TaskHandler taskHandler) {
      this.taskHandler = taskHandler;
    }

    @Override
    public void run() {
      if(countDown>=30){
        taskHandler.sendEmptyMessage(2);
      }else{
        taskHandler.sendEmptyMessage(1);
        countDown++;
      }
    }
  }

   @SuppressLint("HandlerLeak")
   class TaskHandler extends Handler{
    @Override
    public void handleMessage(Message msg) {
      super.handleMessage(msg);
      switch (msg.what){
        case 1:
          //更新倒计时
          if(countDown<10){
            timeShowText.setText("00:0"+countDown);
          }else{
            timeShowText.setText("00:"+countDown);
          }
          break;
        case 2:
          if(timer!=null){
            timer.cancel();
          }
          break;
      }
    }
  }


  /**
   * connect Borsam Device
   */
  public void connect() {
    //BorsamDevice#connect will clear the previously connected data
    //if you don't want,just use BorsamDevice#connect(BorsamBleGattCallback callback,boolean clearData)
    //param:clearData if <code>true</code> will clear the previously connected data
    //<code>false</code> otherwise
    mBorsamDevice.connect(new BorsamBleGattCallback() {
      /**
       * Callback in the main thread
       * Callback this method when the connection starts
       */
      @Override
      public void onStartConnect() {
        setSubtitle(R.string.start_connect);
      }

      /**
       * Callback in the main thread
       * Callback method when connection fails
       */
      @Override
      public void onConnectFail(BorsamDevice borsamDevice, BleException e) {
        setSubtitle(R.string.connect_fail);
      }

      /**
       * Callback in the main thread
       * Callback this method when the connection is successful
       */
      @Override
      public void onConnectSuccess(BorsamDevice borsamDevice, BluetoothGatt bluetoothGatt,
                                   int status) {
        setSubtitle(R.string.connect_success);
        //开始进度条
        circleProgressView.showAnimation(0,100,31*1000);
        ecgStatusText.setText("实时监测中，请保持平静，避免移动");
        getEcgData();
      }

      /**
       * Callback in the main thread
       * Callback this method when the connection is broken
       * @param isActiveDisConnected if <code>true</code> indicate disconnect by {@link BorsamDevice#disConnect()}
       * <code>false</code> disconnect by device
       */
      @Override
      public void onDisConnected(boolean isActiveDisConnected, BorsamDevice borsamDevice,
          BluetoothGatt bluetoothGatt, int status) {
        setSubtitle(R.string.disconnect);
      }
    });
  }

  /**
   * must call method BorsamDevice.getData(...)
   * getBattery
   */
  private void getBattery(){
        mBorsamDevice.getBattery(new BatteryCallback() {
          @Override
          public void onError(BleException e) {
            /**
             * must call method BorsamDevice.getData(...)
             * not receive battery!!!
             * because not received device callback data
             * try again
             */
            getBattery();
          }

          @Override
          public void onSuccess(int batteryPercent) {
            //get battery Success
            updateBattery(batteryPercent);
          }
        });
  }

  @SuppressLint("SetTextI18n")
  private void updateBattery(int batteryPercent){
    batteryText.setText(batteryPercent+"%");
  }

  /**
   * get ecg data
   * Usually, we recommend to delay the acquisition of ECG data after a successful connection.
   * But here, it’s not so particular.
   */
  private void getEcgData() {
    //SimpleBorsamBleDataCallback extend BorsamBleDataCallback
    //It implements onDataChanged and has empty body
    //Generally, you will probably not pay attention onDataChanged
    //BorsamDevice#getData default clear progress last ecg data
    //If you want to progress consolidation,use BorsamDevice#getData(BorsamBleDataCallback callback,boolean keepProgress)
    mBorsamDevice.getData(new SimpleBorsamBleDataCallback() {
      /**
       * data success
       */
      @Override
      public void onDataSuccess() {
        setSubtitle(R.string.getdata_success);
        getBattery();
      }

      /**
       * data failure
       */
      @Override
      public void onDataFailure(BleException e) {
        setSubtitle(R.string.getdata_failure);
      }

      /**
       * data progress
       * @param second unit:s
       */
      @Override
      public void onDataProgress(float second) {
        if (mEnd){
          return;
        }
        if(!isStart){
          timer.schedule(new CountDownTask(taskHandler),0,1000);
          isStart = true;
        }
        setSubtitle(getString(R.string.getdata_progress, second));
        if (second >= TOTAL_TIME) {
          getDataEnd();
        }
      }
    });
  }

  /**
   * get data end
   * Some devices have the second part of the data
   * So we need to judge here
   */
  private void getDataEnd() {
    mEnd = true;
    if (mBorsamDevice.hasDataPartTwo()) {
      mBorsamDevice.setDataPartTwoListener(new DataPartTwoListener() {
        @Override
        public void onDataStart() {
          setSubtitle(R.string.getdata_second_start);
        }

        /**
         * Second part progress
         * @param progress from 0~100
         */
        @Override
        public void onDataProgress(float progress) {
          setSubtitle(getString(R.string.getdata_second_progress, progress));
        }

        @Override
        public void onDataEnd(boolean success) {
          if (success) {
            setSubtitle(getString(R.string.getdata_second_success));
            mBorsamDevice.getCodeAsync(EcgViewActivity.this);
          } else {
            setSubtitle(getString(R.string.getData_second_failure));
          }
        }
      });
    } else {
      mBorsamDevice.getCodeAsync(this);
    }
  }

  private void setSubtitle(CharSequence title) {
   Log.d(EcgViewActivity.TAG,title.toString());
  }

  private void setSubtitle(@StringRes int titleRes) {
    Log.d(EcgViewActivity.TAG,""+titleRes);
  }



  @Override
  protected void onDestroy() {
    super.onDestroy();
    //BorsamDevice#close will disconnect device and clear all datas and listeners
    //if you don't want to clear datas,use BorsamDevice#disconnect

    timer = null;
    taskHandler.removeCallbacks(null);
    taskHandler = null;
  }


  @Override
  public void onSuccess(String deviceCode) {
    Log.d(TAG,deviceCode);
    //上传数据导服务器
    uploadDataToServer(deviceCode);
  }

  private void uploadDataToServer(String deviceCode) {

    String recordData = Base64.encode(mBorsamDevice.getRecordData());
    String ecgValue = ecgValueText.getText().toString();
    //返回结果，并且唤醒flutter
    BlePlugin.getInstance(EcgViewActivity.this).displayEcgData(deviceCode,ecgValue,recordData);
    startActivity(FlutterActivity
            .withCachedEngine(MainActivity.ENGINE_KEY)
            .build(EcgViewActivity.this));

  }


  @Override
  public void onDataFailure(BleException e) {
    Log.d(TAG,e.toString());

  }

  private  class BluetoothStatusReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
      String action = intent.getAction();
      if (action != null) {
        switch (action) {
          case BluetoothAdapter.ACTION_STATE_CHANGED:
            int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
            switch (blueState) {
              case BluetoothAdapter.STATE_TURNING_ON:
                Toast.makeText(context, "蓝牙正在打开", Toast.LENGTH_SHORT).show();
                break;
              case BluetoothAdapter.STATE_ON:
                Toast.makeText(context, "蓝牙已经打开", Toast.LENGTH_SHORT).show();
                connect();
                break;
              case BluetoothAdapter.STATE_TURNING_OFF:
                Toast.makeText(context, "蓝牙正在关闭", Toast.LENGTH_SHORT).show();
                break;
              case BluetoothAdapter.STATE_OFF:
                Toast.makeText(context, "蓝牙已经关闭", Toast.LENGTH_SHORT).show();
                finish();
                break;
            }
            break;

          case BluetoothDevice.ACTION_ACL_CONNECTED:
            Toast.makeText(context, "蓝牙设备已连接", Toast.LENGTH_SHORT).show();
            connect();
            break;

          case BluetoothDevice.ACTION_ACL_DISCONNECTED:
            Toast.makeText(context, "蓝牙设备已断开", Toast.LENGTH_SHORT).show();
            finish();
            break;
        }

      }
    }
  }
}
